package com.sojson.serversocket.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.sojson.serversocket.config.handler.ServerSocketHandlerBusiness;
import com.sojson.serversocket.config.handler.ServerSocketHandlerHeartbeat;
import com.sojson.serversocket.config.handler.ServerSocketHandlerRegister;
import com.sojson.serversocket.util.ServerSocketDataUtil;
import com.sojson.serversocket.util.ServerSocketPoolUtil;
import com.sojson.serversocket.util.bean.ServerSocketConnect;
import com.sojson.serversocket.util.bean.ServerSocketData;
import com.sojson.serversocket.util.enums.EElectricType;
import com.sojson.serversocket.util.enums.EServerSocketDataType;
import com.sojson.util.HexUtil;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * ServerSocket处理器
 *
 * @author liu
 * @date 2024-05-28
 */
@Slf4j
@Sharable
@Component
public class ServerSocketHandler extends ChannelInboundHandlerAdapter {

    @Autowired
    private ServerSocketHandlerRegister register;
    @Autowired
    private ServerSocketHandlerHeartbeat heartbeat;
    @Autowired
    private ServerSocketHandlerBusiness business;

    /**
     * 建立连接时触发的方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    /**
     * 关闭连接时触发的方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Object object = ctx.channel().attr(AttributeKey.valueOf(ServerSocketPoolUtil.ADDR_KEY)).get();
        String addr = null;
        if (object != null) {
            addr = object.toString();
            // 从连接池中删除
            ServerSocketPoolUtil.remove(addr);
        }
        super.channelInactive(ctx);
    }

    /**
     * 发生错误时触发的方法
     *
     * @param ctx
     * @param e
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception {
        Object object = ctx.channel().attr(AttributeKey.valueOf(ServerSocketPoolUtil.ADDR_KEY)).get();
        String addr = null;
        if (object != null) {
            addr = object.toString();
        }
        log.error(new StringBuilder("ServerSocket连接发生错误: ").append(addr).append(",").append(e.getMessage()).toString());
        log.error(e.getMessage(), e);
    }

    /**
     * 收到消息后执行的方法
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String data = null;
        byte[] barr = null;
        // 解析数据
        try {
            ByteBuf buf = (ByteBuf)msg;
            barr = new byte[buf.readableBytes()];
            buf.readBytes(barr);
            data = HexUtil.bytesToHexString(barr).trim();
        } finally {
            ReferenceCountUtil.release(msg);
        }
        log.info(data);
        // 缓存包
        ServerSocketDataUtil.add(ctx, data);

        // 处理包
        while (true) {
            ServerSocketData ServerSocketData = ServerSocketDataUtil.get(ctx);
            if (ServerSocketData == null) {
                break;
            }

            run(ctx, ServerSocketData.getType(), ServerSocketData.getData());
        }
    }

    public void run(ChannelHandlerContext ctx, EServerSocketDataType type, String data) throws Exception {
        String addr = null;
        String addrRever = null;

        // 分类处理
        if (type == EServerSocketDataType.HEARTBEAT_485) {
            // 采集器
            addr = data.substring(4, 18);
            addrRever = HexUtil.reverse(addr).replaceFirst("^0*", "");

            log.info(new StringBuilder("ServerSocket收到采集器心跳包: ").append(addrRever).append(",").append(data).toString());
            ServerSocketConnect connect = ServerSocketPoolUtil.get(addrRever);
            if (connect == null) {
                ServerSocketPoolUtil.put(EElectricType.HARVESTER, addrRever, ctx);
            } else if (connect.getCtx() == null) {
                ServerSocketPoolUtil.put(EElectricType.HARVESTER, addrRever, ctx);
            }
        } else {
            // 4G电表
            if (type == EServerSocketDataType.REGISTER) {
                // 注册包
                addr = data.substring(12, 24);
                addrRever = HexUtil.reverse(addr);

                log.info(
                    new StringBuilder("ServerSocket收到电表注册包: ").append(addrRever).append(",").append(data).toString());
                register.run(ctx, data, addr, addrRever);
            } else if (type == EServerSocketDataType.HEARTBEAT) {
                // 心跳包
                addr = data.substring(12, 24);
                addrRever = HexUtil.reverse(addr);

                log.info(
                    new StringBuilder("ServerSocket收到电表心跳包: ").append(addrRever).append(",").append(data).toString());
                heartbeat.run(ctx, data, addr, addrRever);
            } else if (type == EServerSocketDataType.BUSINESS) {
                addr = data.substring(2, 14);
                addrRever = HexUtil.reverse(addr);

                // 业务包
                business.run(ctx, addr, addrRever, data);
            } else {
            }
        }
    }

}